<template>
    <div class="selector-component">
        <!-- 单选模式 -->
        <el-select v-if="!multiple" v-model="selectedValue" :placeholder="placeholder" :disabled="disabled"
            :clearable="clearable" :filterable="filterable" :remote="remote" :remote-method="remoteMethod"
            :loading="loading" :loading-text="loadingText" :no-match-text="noMatchText" :no-data-text="noDataText"
            :popper-class="popperClass" :reserve-keyword="reserveKeyword" :default-first-option="defaultFirstOption"
            :popper-append-to-body="popperAppendToBody" :automatic-dropdown="automaticDropdown" @change="handleChange"
            @visible-change="handleVisibleChange" @remove-tag="handleRemoveTag" @clear="handleClear" @blur="handleBlur"
            @focus="handleFocus">
            <el-option v-for="item in currentOptions" :key="item[valueKey]" :label="item[labelKey]"
                :value="item[valueKey]" :disabled="item.disabled">
                <div class="option-item">
                    <el-avatar v-if="showAvatar && item.avatar" :src="item.avatar" :size="24" class="option-avatar" />
                    <div class="option-content">
                        <div class="option-label">{{ item[labelKey] }}</div>
                        <div v-if="item.description" class="option-description">
                            {{ item.description }}
                        </div>
                    </div>
                </div>
            </el-option>
        </el-select>

        <!-- 多选模式 -->
        <el-select v-else v-model="selectedValue" :placeholder="placeholder" :disabled="disabled" :clearable="clearable"
            :filterable="filterable" :remote="remote" :remote-method="remoteMethod" :loading="loading"
            :loading-text="loadingText" :no-match-text="noMatchText" :no-data-text="noDataText"
            :popper-class="popperClass" :reserve-keyword="reserveKeyword" :default-first-option="defaultFirstOption"
            :popper-append-to-body="popperAppendToBody" :automatic-dropdown="automaticDropdown" :multiple="multiple"
            :multiple-limit="multipleLimit" :collapse-tags="collapseTags" :collapse-tags-tooltip="collapseTagsTooltip"
            @change="handleChange" @visible-change="handleVisibleChange" @remove-tag="handleRemoveTag"
            @clear="handleClear" @blur="handleBlur" @focus="handleFocus">
            <el-option v-for="item in currentOptions" :key="item[valueKey]" :label="item[labelKey]"
                :value="item[valueKey]" :disabled="item.disabled">
                <div class="option-item">
                    <el-avatar v-if="showAvatar && item.avatar" :src="item.avatar" :size="24" class="option-avatar" />
                    <div class="option-content">
                        <div class="option-label">{{ item[labelKey] }}</div>
                        <div v-if="item.description" class="option-description">
                            {{ item.description }}
                        </div>
                    </div>
                </div>
            </el-option>
        </el-select>

        <!-- 弹窗选择模式 -->
        <el-dialog v-model="dialogVisible" :title="dialogTitle" width="60%" center destroy-on-close>
            <div class="selector-dialog">
                <!-- 搜索栏 -->
                <div class="search-bar">
                    <el-input v-model="searchKeyword" placeholder="请输入关键词搜索" :prefix-icon="Search" clearable
                        @input="handleSearch" />
                </div>

                <!-- 列表内容 -->
                <div class="dialog-content">
                    <el-table ref="tableRef" :data="dialogOptions" :loading="loading"
                        @selection-change="handleSelectionChange" @row-click="handleRowClick">
                        <el-table-column v-if="multiple" type="selection" width="55" align="center" />
                        <el-table-column v-if="showAvatar" label="头像" width="80" align="center">
                            <template #default="{ row }">
                                <el-avatar :src="row.avatar" :size="32" />
                            </template>
                        </el-table-column>
                        <el-table-column :prop="labelKey" :label="labelName" min-width="120" />
                        <el-table-column v-if="type === 'user'" prop="email" label="邮箱" min-width="150" />
                        <el-table-column v-if="type === 'dept'" prop="description" label="描述" min-width="150" />
                        <el-table-column v-if="type === 'dict'" prop="dictValue" label="字典值" min-width="100" />
                    </el-table>
                </div>

                <!-- 分页 -->
                <div class="dialog-pagination">
                    <el-pagination v-model:current-page="dialogPageNum" v-model:page-size="dialogPageSize"
                        :total="dialogTotal" :page-sizes="[10, 20, 50, 100]"
                        layout="total, sizes, prev, pager, next, jumper" @size-change="handlePageSizeChange"
                        @current-change="handlePageChange" />
                </div>
            </div>

            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="dialogVisible = false">取消</el-button>
                    <el-button type="primary" @click="confirmSelection">确定</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
/**
 * 通用选择器组件
 * @author Wu.Liang
 * @description 支持用户、部门、字典等选择，支持单选、多选、弹窗选择
 */
import { ref, computed, watch, onMounted } from 'vue'
import { showMessage } from '@/utils/message'
import { Search } from '@element-plus/icons-vue'
import { userApi } from '@/api/user'

interface Option {
    [key: string]: any
    disabled?: boolean
    avatar?: string
    description?: string
}

interface Props {
    // 绑定值
    modelValue?: any
    // 选择器类型：user-用户, dept-部门, dict-字典
    type: 'user' | 'dept' | 'dict'
    // 是否多选
    multiple?: boolean
    // 占位符
    placeholder?: string
    // 是否禁用
    disabled?: boolean
    // 是否可清空
    clearable?: boolean
    // 是否可搜索
    filterable?: boolean
    // 是否远程搜索
    remote?: boolean
    // 显示头像
    showAvatar?: boolean
    // 选项数据（静态数据）
    options?: Option[]
    // 字典类型（当type为dict时必传）
    dictType?: string
    // 部门层级（当type为dept时）
    deptLevel?: number
    // 显示字段
    labelKey?: string
    // 值字段
    valueKey?: string
    // 标签名称
    labelName?: string
    // 是否弹窗模式
    dialogMode?: boolean
    // 多选限制数量
    multipleLimit?: number
    // 多选标签折叠
    collapseTags?: boolean
    // 折叠标签提示
    collapseTagsTooltip?: boolean
}

const props = withDefaults(defineProps<Props>(), {
    multiple: false,
    placeholder: '请选择',
    disabled: false,
    clearable: true,
    filterable: true,
    remote: false,
    showAvatar: false,
    options: () => [],
    labelKey: 'name',
    valueKey: 'id',
    labelName: '名称',
    dialogMode: false,
    multipleLimit: 0,
    collapseTags: false,
    collapseTagsTooltip: false
})

const emit = defineEmits<{
    'update:modelValue': [value: any]
    'change': [value: any]
}>()

// 响应式数据
const loading = ref(false)
const currentOptions = ref<Option[]>([])
const dialogVisible = ref(false)
const dialogOptions = ref<Option[]>([])
const dialogTotal = ref(0)
const dialogPageNum = ref(1)
const dialogPageSize = ref(20)
const searchKeyword = ref('')
const selectedItems = ref<Option[]>([])
const tableRef = ref()

// 计算属性
const selectedValue = computed({
    get: () => props.modelValue,
    set: (value) => emit('update:modelValue', value)
})

const dialogTitle = computed(() => {
    const typeMap = {
        user: '选择用户',
        dept: '选择部门',
        dict: '选择字典'
    }
    return typeMap[props.type] || '选择'
})

// 选择器配置
const loadingText = '加载中...'
const noMatchText = '无匹配数据'
const noDataText = '无数据'
const popperClass = 'selector-popper'
const reserveKeyword = false
const defaultFirstOption = false
const popperAppendToBody = true
const automaticDropdown = false

// 初始化
onMounted(() => {
    if (props.options.length > 0) {
        currentOptions.value = props.options
    } else {
        loadOptions()
    }
})

// 监听类型变化
watch(() => props.type, () => {
    currentOptions.value = []
    loadOptions()
})

// 监听字典类型变化
watch(() => props.dictType, () => {
    if (props.type === 'dict') {
        loadOptions()
    }
})

// 加载选项数据
const loadOptions = async() => {
    if (props.options.length > 0) {
        currentOptions.value = props.options
        return
    }

    loading.value = true
    try {
        let data: Option[] = []

        switch (props.type) {
        case 'user':
            data = await loadUsers()
            break
        case 'dept':
            data = await loadDepts()
            break
        case 'dict':
            data = await loadDictItems()
            break
        }

        currentOptions.value = data
    } catch (error) {
        console.error('加载选项数据失败:', error)
        showMessage({ type: 'error', message: '加载数据失败' })
    } finally {
        loading.value = false
    }
}

// 加载用户数据
const loadUsers = async(): Promise<Option[]> => {
    // 模拟API调用
    return [
        { id: 1, name: '张三', email: 'zhangsan@example.com', avatar: '' },
        { id: 2, name: '李四', email: 'lisi@example.com', avatar: '' },
        { id: 3, name: '王五', email: 'wangwu@example.com', avatar: '' }
    ]
}

// 加载部门数据
const loadDepts = async(): Promise<Option[]> => {
    // 模拟API调用
    return [
        { id: 1, name: '技术部', description: '技术研发部门' },
        { id: 2, name: '市场部', description: '市场营销部门' },
        { id: 3, name: '人事部', description: '人力资源部门' }
    ]
}

// 加载字典数据
const loadDictItems = async(): Promise<Option[]> => {
    if (!props.dictType) {
        return []
    }

    // 模拟API调用
    return [
        { id: 1, name: '选项1', dictValue: 'option1' },
        { id: 2, name: '选项2', dictValue: 'option2' },
        { id: 3, name: '选项3', dictValue: 'option3' }
    ]
}

// 远程搜索方法
const remoteMethod = async(query: string) => {
    if (!query) {
        loadOptions()
        return
    }

    loading.value = true
    try {
        // 模拟远程搜索
        const allOptions = await loadOptions()
        currentOptions.value = currentOptions.value.filter(item =>
            item[props.labelKey].toLowerCase().includes(query.toLowerCase())
        )
    } catch (error) {
        console.error('搜索失败:', error)
    } finally {
        loading.value = false
    }
}

// 事件处理
const handleChange = (value: any) => {
    emit('change', value)
}

const handleVisibleChange = (visible: boolean) => {
    if (visible && props.dialogMode) {
        dialogVisible.value = true
    }
}

const handleRemoveTag = (value: any) => {
    // 处理多选标签移除
}

const handleClear = () => {
    emit('update:modelValue', props.multiple ? [] : null)
}

const handleBlur = () => {
    // 失焦处理
}

const handleFocus = () => {
    // 获焦处理
}

// 弹窗相关方法
const handleSearch = async() => {
    dialogPageNum.value = 1
    await loadDialogData()
}

const loadDialogData = async() => {
    loading.value = true
    try {
        // 模拟分页搜索API
        const allData = await loadOptions()
        let filteredData = allData

        if (searchKeyword.value) {
            filteredData = allData.filter(item =>
                item[props.labelKey].toLowerCase().includes(searchKeyword.value.toLowerCase())
            )
        }

        dialogTotal.value = filteredData.length
        const start = (dialogPageNum.value - 1) * dialogPageSize.value
        const end = start + dialogPageSize.value
        dialogOptions.value = filteredData.slice(start, end)
    } catch (error) {
        console.error('加载弹窗数据失败:', error)
    } finally {
        loading.value = false
    }
}

const handleSelectionChange = (selection: Option[]) => {
    selectedItems.value = selection
}

const handleRowClick = (row: Option) => {
    if (!props.multiple) {
        selectedItems.value = [row]
    }
}

const handlePageChange = (page: number) => {
    dialogPageNum.value = page
    loadDialogData()
}

const handlePageSizeChange = (size: number) => {
    dialogPageSize.value = size
    dialogPageNum.value = 1
    loadDialogData()
}

const confirmSelection = () => {
    if (props.multiple) {
        const values = selectedItems.value.map(item => item[props.valueKey])
        emit('update:modelValue', values)
    } else {
        const value = selectedItems.value.length > 0 ? selectedItems.value[0][props.valueKey] : null
        emit('update:modelValue', value)
    }
    dialogVisible.value = false
    emit('change', selectedValue.value)
}

// 暴露方法
defineExpose({
    loadOptions,
    clearSelection: handleClear
})
</script>

<style lang="scss" scoped>
.selector-component {
    width: 100%;

    .option-item {
        display: flex;
        align-items: center;
        padding: 4px 0;

        .option-avatar {
            margin-right: 8px;
        }

        .option-content {
            flex: 1;

            .option-label {
                font-size: 14px;
                color: var(--el-text-color-primary);
            }

            .option-description {
                font-size: 12px;
                color: var(--el-text-color-secondary);
                margin-top: 2px;
            }
        }
    }

    .selector-dialog {
        .search-bar {
            margin-bottom: 16px;
        }

        .dialog-content {
            margin-bottom: 16px;
            max-height: 400px;
            overflow-y: auto;
        }

        .dialog-pagination {
            display: flex;
            justify-content: center;
        }
    }
}
</style>

<style lang="scss">
.selector-popper {
    .el-select-dropdown__item {
        height: auto;
        padding: 8px 20px;
    }
}
</style>
